package com.curluin.approximateShapes;

import java.util.Vector;

import android.util.Log;

import com.curluin.controll.Controller;
import com.curluin.math.MyMatrix;
import com.curluin.math.MyVector;

public abstract class ApproximateShape {

	protected static String LOG_TAG = "ApproximateShape";
	protected Vector<MyVector> scanData;
	private static final float epsilon=0.00001f;
	
	
	/**
	 * Scans the shape with the given Sample rate.
	 * Each pair of two Vectors define a line which is occupied by this shape (even=start point,uneven=end point) . 
	 * The sum of all lines covers the whole shape.
	 * @param sampleRate
	 * @return each two Vectors define one line
	 */
	
	public Vector<MyVector> scan(float sampleRate, boolean recompute){
		Vector<MyVector> res  = new Vector<MyVector>();
		if(recompute||scanData==null) res=initializeScanData(sampleRate);
		else res=getScanData();
		return res;
	}
	
	/**
	 * Scans the shape with the given Sample rate.
	 * Each pair of two Vectors define a line which is occupied by this shape (even=start point,uneven=end point) . 
	 * The sum of all lines covers the whole shape.
	 * @param sampleRate
	 * @return each two Vectors define one line
	 */
	protected abstract Vector<MyVector> initializeScanData(float sampleRate);

	
	/**
	 * Translates the scan by the specified vector.
	 * @param translation vector to add to all intersections
	 * @return returns new translated scan data
	 */
	public Vector<MyVector> translateScanData(MyVector translation) {
		if(scanData==null){
			initializeScanData(Controller.getGridFieldWidth());
			Log.e(LOG_TAG, "Cannot Translate Scandata because Scandata does not exist -> Calling com.curluin.approximateShapes.ApproximateShape.initializeScanData(float)");
			return null;
		}
		for(int i=0; i<scanData.size();i++){
			MyVector v= scanData.get(i).add(translation);
			scanData.set(i, v);
			
		}
		return scanData;
	}
	
	
	/**
	 * Rotates scandata
	 * @param rot rotation
	 * @param center of object
	 * @return
	 */
	public Vector<MyVector> rotateScanData(MyVector rot, MyVector center){
		Log.w(LOG_TAG, "rotate Scandata: "+rot);
		if(scanData==null){
			Log.e(LOG_TAG, "Cannot Rotate Scandata because Scandata does not exist -> Calling com.curluin.approximateShapes.ApproximateShape.initializeScanData(float)");
			initializeScanData(Controller.getGridFieldWidth());
		}
		float xRotAngle = (float) (rot.get(0)*Math.PI/180f);
		float yRotAngle = (float) (rot.get(1)*Math.PI/180f);
		float zRotAngle = (float) (rot.get(2)*Math.PI/180f);
		MyVector zRotAxis=MyVector.makeVector3(0, 0, 1);
		MyVector yRotAxis=MyVector.makeVector3(0, 1, 0);
		MyVector xRotAxis=MyVector.makeVector3(1, 0, 0);
		MyMatrix zrot = MyMatrix.getRotationMatrix(zRotAxis, zRotAngle);
		MyMatrix yrot = MyMatrix.getRotationMatrix(yRotAxis, yRotAngle);
		MyMatrix xrot = MyMatrix.getRotationMatrix(xRotAxis, xRotAngle);
		
		for(int i=0; i<scanData.size();i++){
			MyVector v= scanData.get(i);
			v.set(1, center.get(1));
//			Log.e(LOG_TAG, " v before all: "+v);
			v=v.subtract(center);
//			Log.e(LOG_TAG, " v before rotz: "+v);
			v=xrot.multiply(v);
			v=yrot.multiply(v);
			v=zrot.multiply(v);
//			Log.e(LOG_TAG, " v after rot: "+v);
			v=v.add(center);
//			Log.e(LOG_TAG, " v after all: "+v);
			scanData.set(i, v);
		}
		
		return scanData;
	}
	
	public Vector<MyVector> getScanData(){
		return scanData;
	}

	public static float cutXBackToModelSpace(float xCoord){
		float res= xCoord; 
		if(xCoord>Controller.xModelRange)res= Controller.xModelRange-epsilon;
		else if(xCoord<Controller.xModelOrigin)res= Controller.xModelOrigin;
		return res;
	}
	public static float cutZBackToModelSpace(float zCoordinate){
		float zCoord=Math.abs(zCoordinate);
		float res= zCoord;
		if(zCoord>Controller.zModelRange){
			Log.w(LOG_TAG,"Z-Coordinate out of model-range: "+zCoord+"<"+Controller.zModelRange);
			res= Controller.zModelRange-epsilon;
		}
		else if(zCoord<Controller.zModelOrigin){
			Log.w(LOG_TAG,"Z-Coordinate out of model-range: "+zCoord+">"+Controller.zModelOrigin);
			res= Controller.zModelOrigin;
		}
		return -res;
	}
	
}
